'''
Created on May 2, 2013

@author: thrabe
'''



from pytom.angles.angle import AngleObject


class GlobalSampling(AngleObject):
    _defaultShells       = 1
    _defaultIncrement    = 10
    
    def __init__(self,filename='',inputIsInRadians=True,refinementParameters=None):
        """
        ___init__:
        @param filename: Filename of em file storing rotations. New files must have the naming (angles_INCREMENT_NUMBERROTATIONS.em) below. Set to either one of these:  
        angles_3_553680.em angles_07_45123.em angles_11_15192.em angles_12.85_7112.em angles_17.86_3040.em angles_18_3040.em angles_19.95_1944.em  angles_25.25_980.em angles_35.76_320.em angles_38.53_256.em angles_50_100.em angles_90_26.em angles_inf_0.em
        @param inputIsInRadians: Are the input values in radiants (True is assumed as default)
        @param refinementParameters: Parameters for next refinement step 
        @author: Thomas Hrabe  
        """
        from pytom.tools.files import checkFileExists,getPytomPath
        import os
        if checkFileExists(filename):
            self._filename = filename
        else:
            
            if os.sep in filename:
                #parse angle file name out of filename
                splitName = filename.split(os.sep)
                filename = splitName[-1]
            
            if not filename[-3:] == '.em':
                filename = filename + '.em'
            
            self._filename = getPytomPath() + '/angles/angleLists/' + filename
        
        if checkFileExists(self._filename):
            self.readRotationsFromEMFile(self._filename,inputIsInRadians)
            
        self._currentIndex = 0
        
        self._refinementParameters = refinementParameters or [self._defaultShells,self._defaultIncrement]#shells,increment
        
        
    def getFileName(self):
        return self._filename
    
    def getRefinementParameters(self):
        return self._refinementParameters
    
    def getIncrement(self):
        """
        getIncrement: Returns the increment of the rotation list currently used
        """
        parts = self._filename.split('_')
        return float(parts[1])
        
        
    def readRotationsFromEMFile(self,filename,inputIsInRadians=True):
        """
        readRotationsFromEMFile: Reads rotations from EM file and optionally converts them from radians to degrees
        @param filename: Name of EM file
        @param inputIsInRadians: 
        @type inputIsInRadians: bool   
        """
        self._angleList = [] 
        
        if not filename == '':
            import pytom_volume
            from pytom.angles.angle import rad2deg
            
            try:
                angs = pytom_volume.read(filename)
            except RuntimeError:
                from pytom.tools.files import checkFileExists,getPytomPath
                
                if not checkFileExists(filename):
                    filename = getPytomPath() + '/angles/angleLists/' + filename
                
                angs = pytom_volume.read(filename)
              
            for i in range(angs.sizeY()):
                phi = angs.getV(0,i,0)
                psi = angs.getV(1,i,0)
                the = angs.getV(2,i,0)
            
                if inputIsInRadians:
                    phi = phi * rad2deg
                    psi = psi * rad2deg
                    the = the * rad2deg
            
                self._angleList.append([phi,psi,the])

                
    def nextRotation(self):
        """
        nextRotation : 
        @return: Either [None,None,None] if all rotations were scanned or [phi psi theta] for the next rotation
        @author: Thomas Hrabe
        """
        rotation = [None,None,None]
        
        if self._currentIndex < len(self._angleList):
            from pytom.angles.angle import rad2deg
            
            rotation = self._angleList[self._currentIndex]
        
            self._currentIndex = self._currentIndex +1
        
        return rotation
    
    def getRotations(self):
        """
        getRotations: Get the list of rotations
        """
        return self._angleList
    
    def fromXML(self,xmlObj):
        """
        fromXML: Sets attributes of self to those defined by xmlObj
        @param xmlObj: A XML attribute as generated by toXML 
        @author: Thomas Hrabe
        """
        from lxml.etree import _Element
        
        if xmlObj.__class__ != _Element:
            raise ParameterError('You must provide a valid XML-GlobalSampling object.')

        if xmlObj.tag == 'Angles':
            angles = xmlObj
        else:
            angles = xmlObj.xpath('Angles')
        
            if len(angles) == 0:
                from pytom.basic.exceptions import ParameterError
                raise ParameterError("This XML is not an GlobalSampling DOM.")
            angles = angles[0]
        
        self._currentIndex =0
        
        parameters = angles.xpath('RefinementParameters')
        self._refinementParameters = []
        if len(parameters) == 1:
            parameters = parameters[0]
            
            self._refinementParameters.append(float(parameters.get('Shells')))
            self._refinementParameters.append(float(parameters.get('Increment')))
        else:
            self._refinementParameters.append(self._defaultShells)
            self._refinementParameters.append(self._defaultIncrement)
            
        self._filename = angles.get('File')
        
        self.readRotationsFromEMFile(self._filename)
            
    def toXML(self):
        """
        toXML : Compiles a XML attribute from the Object
        @author: Thomas Hrabe
        """
        from lxml import etree
            
        rotations_element = etree.Element("Angles")
        rotations_element.set("Type",'GlobalSampling')
        rotations_element.set("File",self._filename)
        
        if self._refinementParameters[0] != self._defaultShells or self._refinementParameters[1] != self._defaultIncrement:
            parameter_element = etree.Element("RefinementParameters")
            
            parameter_element.set('Shells',str(float(self._refinementParameters[0])))
            parameter_element.set('Increment',str(float(self._refinementParameters[1])))
        
            rotations_element.append(parameter_element)

        return rotations_element
    
    def focusRotation(self,rotation=None,refinementAngle = None):
        """
        focusRotation: Returns new object which focuses on the rotation provided
        @param rotation: The rotation to focus on
        @return: New angle object
        @rtype: L{pytom.angles.AngleObject}
        @author: Thomas Hrabe 
        """
        return GlobalSampling(self._filename)
    
    
    def numberRotations(self):
        """
        numberRotations: Returns the total number of rotations for the current object
        @author: Thomas Hrabe 
        """
        return len(self._angleList) 
    
    def __getitem__(self,key):
        if isinstance(key, int):
            
            if key < self.numberRotations():
                return self._angleList[key];
            else:
                raise IndexError('Index out of range.');
            
        elif key.__class__ == slice:

            start = key.start
            stop = key.stop
            step = key.step
            print(key)
            if start ==None: start= 0
            if step == None: step = 1

            if stop ==None or stop >= 922337203685477580:
                stop = int(self.numberRotations())
                
            rotations = []
            for r in self._angleList[int(start):int(stop):int(step)]:
                rotations.append(r)
                
            return rotations
        else:
            assert False
    
    def copy(self,rotation):
        
        return GlobalSampling(self._filename,refinementParameters=self._refinementParameters,oldRotations = self._oldRotations)
    
    def setStartRotation(self,rotation=None):
        return self
    
    def reset(self):
        self._currentIndex = 0
